package cqrtplm.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.PageInfo;
import com.hustcad.plm.pdm.common.model.dto.ObjRenameDTO;
import com.hustcad.plm.pdm.common.model.vo.search.ResultEntityVO;
import com.hustcad.plm.pdm.common.service.TyplmObjsRenameService;
import com.hustcad.plm.pdm.flowbusiness.model.entity.FlowObject;
import com.hustcad.plm.pdm.flowbusiness.model.entity.WorkFlowObjectPackage;
import com.hustcad.plm.pdm.iba.model.dto.SaveObjIBADTO;
import com.hustcad.plm.pdm.iba.service.TyplmAttributeValueService;
import com.hustcad.plm.pdm.workflow.model.entity.WorkFlowContainerView;
import com.hustcad.plm.pdm.workflow.service.TyplmWorkFlowContainerService;
import com.ty.basic.constant.TableTypeConstrant;
import com.ty.basic.dto.constraint.IbaDTO;
import com.ty.basic.entity.CTyEntityBaseDO;
import com.ty.basic.entity.org.UserDO;
import com.ty.basic.service.snow.SnowflakeIdComponent;
import com.ty.basic.session.TyAccountContext;
import com.ty.basic.vo.AttributeVO;
import cqrtplm.constant.RTErrorCodeEnum;
import cqrtplm.dto.GenerateDescriptionRuleDto;
import cqrtplm.dto.UserQueryDTO;
import cqrtplm.entity.DescribeSpliceRuleDO;
import cqrtplm.entity.MaterialSapSyncDO;
import cqrtplm.mapper.DescribeSpliceRuleMapper;
import cqrtplm.mapper.MaterialSapSyncMapper;
import cqrtplm.service.AttributePropagationService;
import cqrtplm.service.CodeSequenceService;
import cqrtplm.service.QueryPartService;
import cqrtplm.vo.DescriptionVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AttributePropagationServiceImpl implements AttributePropagationService {

    @Resource
    private TyplmWorkFlowContainerService typlmWorkFlowContainerService;

    @Resource
    private QueryPartService queryPartService;

    @Resource
    private SnowflakeIdComponent snowflakeIdComponent;

    @Resource
    private TyplmAttributeValueService typlmAttributeValueService;

    @Resource
    private DescribeSpliceRuleMapper describeSpliceRuleMapper;

    @Resource
    private CodeSequenceService codeSequenceService;

    @Resource
    private MaterialSapSyncMapper materialSapSyncMapper;

    @Resource
    private TyplmObjsRenameService typlmObjsRenameService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void attributePropagation(String workFlowContainerId) {
        WorkFlowContainerView workFlowContainerView = typlmWorkFlowContainerService.getWorkFlowContainerDetailByPrimaryKey(
                new BigInteger(workFlowContainerId));
        if (workFlowContainerView instanceof WorkFlowObjectPackage) {
            WorkFlowObjectPackage workFlowObjectPackage = (WorkFlowObjectPackage) workFlowContainerView;
            List<FlowObject> flowObjectList = workFlowObjectPackage.getFlowObjectList();
            if (CollUtil.isEmpty(flowObjectList)) {
                return;
            }
            List<String> typeNameList = new ArrayList<>();
            typeNameList.add(TableTypeConstrant.TY_PART_OTYPE + "|PatternCode");
            typeNameList.add(TableTypeConstrant.TY_PART_OTYPE + "|MaterialCode");
            typeNameList.add(TableTypeConstrant.TY_PART_OTYPE + "|EBOM_NUM");
            flowObjectList.removeIf(m -> !m.getRefObjectOtype().equalsIgnoreCase(TableTypeConstrant.TY_PART_OTYPE));
            List<FlowObject> drawingObjects = flowObjectList.stream().filter(
                    obj -> "产品型谱".equals(obj.getType())).collect(
                    Collectors.toList());
            for (FlowObject flowObject : drawingObjects) {
                List<AttributeVO> partAttributeVO = typlmAttributeValueService.getAttrValueTableByEntitys(
                        Collections.singletonList(flowObject.getRefObjectOid()), TableTypeConstrant.TY_PART_OTYPE).get(
                        flowObject.getRefObjectOid().toString());
                List<String> ibaNameList = new ArrayList<>();

                Map<BigInteger, AttributeVO> defaultValueMap = new HashMap<>();
                for (AttributeVO attributeVO : partAttributeVO) {
                    ibaNameList.add(attributeVO.getAttributeEnName());
                    defaultValueMap.put(new BigInteger(attributeVO.getAttributeOid()), attributeVO);
                }
                List<ResultEntityVO> allList = new ArrayList<>();
                for (String typeName : typeNameList) {
                    String refObjectNumber = flowObject.getRefObjectNumber();
                    UserQueryDTO userQueryDTO = new UserQueryDTO();
                    UserQueryDTO.ConditionGroup conditionGroup = new UserQueryDTO.ConditionGroup();
                    UserQueryDTO.Condition condition = new UserQueryDTO.Condition();
                    condition.setOperator("equals");
                    condition.setValue(refObjectNumber);
                    conditionGroup.setLogic("and");
                    conditionGroup.setConditions(Collections.singletonList(condition));
                    userQueryDTO.setConditions(Collections.singletonMap("devCode", conditionGroup));
                    userQueryDTO.setPageNum(1);
                    userQueryDTO.setPageSize(9999999);
                    userQueryDTO.setTypeInthid(typeName);
                    userQueryDTO.setIsQueryDTO("1");
                    PageInfo<ResultEntityVO> resultEntityVOPageInfo = queryPartService.queryPartData(userQueryDTO, Boolean.FALSE, Boolean.TRUE);
                    List<ResultEntityVO> list = resultEntityVOPageInfo.getList();
                    allList.addAll(list);
                }
                // 收集所有ResultEntityVO对象，按照classificationoid分组（将BigInteger转换为String）
                Map<String, List<ResultEntityVO>> partMap = allList.stream()
                        .collect(Collectors.groupingBy(
                                result -> result.getClassificationoid().toString(), // 将BigInteger转换为String
                                Collectors.toList()
                        ));

                if (CollUtil.isEmpty(partMap)) {
                    return;
                }
                Set<String> classOidList = partMap.keySet();
                // 收集partMap中所有ResultEntityVO的oid，过滤空值
                List<BigInteger> partOidList = partMap.values().stream()
                        .filter(Objects::nonNull)  // 过滤空的List
                        .flatMap(List::stream)
                        .filter(Objects::nonNull)  // 过滤空的ResultEntityVO
                        .map(ResultEntityVO::getOid)
                        .filter(Objects::nonNull)  // 过滤空的oid
                        .collect(Collectors.toList());

                //收集分类实例出来的part对象的oid，根据oid查询实例化对象的iba
                Map<String, List<AttributeVO>> ibaValuePart = typlmAttributeValueService.getAttrValueTableByEntitys(
                        partOidList, TableTypeConstrant.TY_PART_OTYPE);

                //查询拼接规则
                List<DescribeSpliceRuleDO> describeSpliceRuleDOS = describeSpliceRuleMapper.queryDescribeSpliceRuleBatch(
                        classOidList, TableTypeConstrant.TY_CLASSIFICATION_OTYPE);
                Map<String, DescribeSpliceRuleDO> describeSpliceRuleDOMap = describeSpliceRuleDOS.stream()
                        .collect(Collectors.toMap(DescribeSpliceRuleDO::getClassOid, Function.identity()));


                //查询出来存在拼接的分类
                Map<String, List<String>> describeMap = new HashMap<>();
                for (Map.Entry<String, DescribeSpliceRuleDO> entry : describeSpliceRuleDOMap.entrySet()) {
                    String key = entry.getKey();
                    String displayRules = entry.getValue().getDescribeRules();
                    // 使用Stream过滤匹配的ibaName
                    List<String> matchedIbaNames = ibaNameList.stream()
                            .filter(displayRules::contains)
                            .collect(Collectors.toList());
                    // 只有当有匹配项时才放入map
                    if (!matchedIbaNames.isEmpty()) {
                        describeMap.put(key, matchedIbaNames);
                    }
                }
                Map<String, List<AttributeVO>> ebomIbaPartMap = new HashMap<>();

                Map<String, List<String>> map = new HashMap<>();
                List<String> partOidS = new ArrayList<>();
                List<SaveObjIBADTO> objWithIbaList = new ArrayList<>();
                // 批量更新属性
                for (Map.Entry<String, List<ResultEntityVO>> entry : partMap.entrySet()) {
                    List<ResultEntityVO> value = entry.getValue();
                    for (ResultEntityVO vo : value) {
                        boolean isEBom = false;
                        if ("EBOM_NUM".equals(vo.getTypeLogicalidentifier())) {
                            isEBom = true;
                        }
                        List<AttributeVO> list = new ArrayList<>();
                        SaveObjIBADTO saveObjIBADTO = new SaveObjIBADTO();
                        List<IbaDTO> ibaDTOList = new ArrayList<>();
                        List<AttributeVO> attributeVOS = ibaValuePart.get(vo.getOid().toString());
                        for (AttributeVO attributeVO : attributeVOS) {
                            String attributeOid = attributeVO.getAttributeOid();
                            if (defaultValueMap.containsKey(new BigInteger(attributeOid))) {
                                AttributeVO attributeVO1 = defaultValueMap.get(new BigInteger(attributeOid));
                                String attributeValue = attributeVO.getAttributeValue();
                                String attributeValue1 = attributeVO1.getAttributeValue();
                                if (!StringUtils.equals(attributeValue, attributeValue1)) {
                                    if (isEBom) {
                                        String attributeEnName = attributeVO1.getAttributeEnName();
                                        if ("productType".equals(attributeEnName) || "HistoricalModels".equals(
                                                attributeEnName)) {
                                            list.add(attributeVO1);
                                        }
                                    }
                                    IbaDTO ibaDTO = new IbaDTO();
                                    ibaDTO.setKey(attributeVO.getAttributeEnName());
                                    ibaDTO.setValue(attributeVO1.getAttributeValue());
                                    ibaDTOList.add(ibaDTO);
                                    map.put(attributeVO.getAttributeEnName(),
                                            Collections.singletonList(attributeVO1.getAttributeValue()));
                                }
                            }
                        }
                        if (CollUtil.isNotEmpty(list)) {
                            ebomIbaPartMap.put(vo.getOid().toString(), list);
                        }
                        if (CollUtil.isNotEmpty(ibaDTOList)) {
                            partOidS.add(vo.getOid().toString());
                            saveObjIBADTO.setObjIbaList(ibaDTOList);
                            saveObjIBADTO.setCTyEntityBaseDO(new CTyEntityBaseDO(vo.getOid(), vo.getOtype()));
                            objWithIbaList.add(saveObjIBADTO);
                        }
                    }
                }
                typlmAttributeValueService.batchSaveIBAByObjsNoConstraint(objWithIbaList, false);

                Map<String, String> errorMap = new HashMap<>();

                List<RTClassificationServiceImpl.DescriptionResult> effectiveDescriptions = new ArrayList<>();
                objWithIbaList = new ArrayList<>();
                //分类的oid集合
                Set<String> classOidS = describeMap.keySet();
                for (String classOid : classOidS) {
                    if (!partMap.containsKey(classOid)) {
                        continue;
                    }
                    List<ResultEntityVO> resultEntityVOS = partMap.get(classOid);
                    Map<String, DescriptionVO> descriptionVOMap = new HashMap<>();
                    Map<BigInteger, String> partNumberOidMap = new HashMap<>();
                    for (ResultEntityVO resultEntityVO : resultEntityVOS) {
                        BigInteger oid = resultEntityVO.getOid();
                        if (!partOidS.contains(oid.toString())) {
                            continue;
                        }
                        List<AttributeVO> attributeVOS = ibaValuePart.get(oid.toString());
                        Map<String, List<String>> ibaMap = new HashMap<>();
                        for (AttributeVO attributeVO : attributeVOS) {
                            List<String> list = new ArrayList<>();
                            list.add(attributeVO.getAttributeValue());
                            String ibaName = attributeVO.getAttributeEnName();
                            if (ibaMap.containsKey(ibaName)) {
                                List<String> strings = ibaMap.get(ibaName);
                                strings.add(attributeVO.getAttributeValue());
                                ibaMap.put(ibaName, strings);
                            } else {
                                ibaMap.put(ibaName, list);
                            }
                        }
                        ibaMap.putAll(map);
                        GenerateDescriptionRuleDto generateDescriptionRuleDto = new GenerateDescriptionRuleDto();
                        generateDescriptionRuleDto.setIbaMap(ibaMap);
                        generateDescriptionRuleDto.setType(resultEntityVO.getTypeLogicalidentifier());
                        generateDescriptionRuleDto.setClassId(classOid);
                        generateDescriptionRuleDto.setIsCheckCurrentDescriptionIfExist("false");
                        if ("MaterialCode".equals(resultEntityVO.getTypeLogicalidentifier())) {
                            generateDescriptionRuleDto.setIsMaterial("true");
                        } else {
                            generateDescriptionRuleDto.setIsMaterial("false");
                        }
                        log.info(">>>>>>>>>>>>>>>{}", resultEntityVO.getObjectNumber());
                        DescriptionVO descriptionVO;
                        try {
                            descriptionVO = codeSequenceService.generateDescriptionRule(
                                    generateDescriptionRuleDto, Boolean.TRUE);
                        } catch (Exception e) {
                            errorMap.put(resultEntityVO.getObjectNumber(), e.getLocalizedMessage());
                            continue;
                        }
                        //收集图样代号
                        if ("PatternCode".equals(resultEntityVO.getTypeLogicalidentifier())) {
                            descriptionVOMap.put(resultEntityVO.getObjectNumber(), descriptionVO);
                        }
                        SaveObjIBADTO saveObjIBADTO = new SaveObjIBADTO();
                        List<IbaDTO> ibaDTOList = new ArrayList<>();
                        IbaDTO ibaDTO = new IbaDTO();
                        if ("MaterialCode".equals(resultEntityVO.getTypeLogicalidentifier())) {
                            partNumberOidMap.put(resultEntityVO.getOid(), resultEntityVO.getObjectNumber());
                            ibaDTO.setKey("MaterialCodeDescription");
                        } else {
                            ibaDTO.setKey("CompleteDescription");
                        }
                        ibaDTO.setValue(descriptionVO.getSystemDescription());
                        ibaDTOList.add(ibaDTO);
                        ibaDTO = new IbaDTO();
                        ibaDTO.setKey("Description");
                        ibaDTO.setValue(descriptionVO.getIbaDescription());
                        ibaDTOList.add(ibaDTO);
                        saveObjIBADTO.setObjIbaList(ibaDTOList);
                        // 但只在满足特定条件时收集描述信息
                        if ("MaterialCode".equals(resultEntityVO.getTypeLogicalidentifier()) || "Standard".equals(
                                resultEntityVO.getTypeLogicalidentifier())) {
                            String lifecyclestagekey = resultEntityVO.getLifecyclestagekey();
                            log.info(">>>>>>>>>>>>{}", resultEntityVO.getObjectNumber());
                            log.info(">>>>>>>>>>>>{}", lifecyclestagekey);
                            if ("RELEASED".equals(lifecyclestagekey)) {
                                RTClassificationServiceImpl.DescriptionResult descriptionResult = new RTClassificationServiceImpl.DescriptionResult();
                                descriptionResult.setResultEntityVO(resultEntityVO);
                                descriptionResult.setIbaDTOList(ibaDTOList);
                                descriptionResult.setGenerateTime(new Date());
                                effectiveDescriptions.add(descriptionResult);
                            }
                        }
                        saveObjIBADTO.setCTyEntityBaseDO(
                                new CTyEntityBaseDO(resultEntityVO.getOid(), resultEntityVO.getOtype()));
                        objWithIbaList.add(saveObjIBADTO);
                    }
                    for (SaveObjIBADTO saveObjIBADTO : objWithIbaList) {
                        BigInteger oid = saveObjIBADTO.getCTyEntityBaseDO().getOid();
                        if (partNumberOidMap.containsKey(oid)) {
                            String partNumber = partNumberOidMap.get(oid);
                            for (Map.Entry<String, DescriptionVO> entry : descriptionVOMap.entrySet()) {
                                String key = entry.getKey();
                                if (partNumber.contains(key)) {
                                    DescriptionVO descriptionVO = entry.getValue();
                                    List<IbaDTO> objIbaList = saveObjIBADTO.getObjIbaList();
                                    for (IbaDTO ibaDTO : objIbaList) {
                                        String value = ibaDTO.getValue();
                                        if ("MaterialCodeDescription".equals(ibaDTO.getKey())) {
                                            ibaDTO.setValue(descriptionVO.getSystemDescription() + " ; " + value);
                                        } else if ("CompleteDescription".equals(ibaDTO.getKey())) {
                                            ibaDTO.setValue(descriptionVO.getIbaDescription() + " ; " + value);
                                        }
                                    }
                                    IbaDTO ibaDTO = new IbaDTO();
                                    ibaDTO.setKey("Common_Attributes|1757215074349");//完整描述
                                    ibaDTO.setValue(descriptionVO.getSystemDescription());
                                    objIbaList.add(ibaDTO);
                                    ibaDTO = new IbaDTO();
                                    ibaDTO.setKey("PatternCodeDescription");//拼接描述
                                    ibaDTO.setValue(descriptionVO.getIbaDescription());
                                    objIbaList.add(ibaDTO);
                                }
                            }
                        }
                    }
                }
                if (CollUtil.isNotEmpty(errorMap)) {
                    log.info("errorMap>>>>>>>>>>>>{}", errorMap);
                    throw RTErrorCodeEnum.DEV_CODE_EXIST.getException(errorMap.toString());
                }
                typlmAttributeValueService.batchSaveIBAByObjsNoConstraint(objWithIbaList, false);

                //todo
                List<ObjRenameDTO> objRenameDTOS = new ArrayList<>();
                for (Map.Entry<String, List<AttributeVO>> entry : ebomIbaPartMap.entrySet()) {
                    String key = entry.getKey();
                    List<AttributeVO> value = entry.getValue();
                    ObjRenameDTO objRenameDTO = new ObjRenameDTO();
                    Map<String, List<String>> ibaAttribute = value.stream()
                            .collect(Collectors.groupingBy(
                                    AttributeVO::getAttributeEnName,
                                    Collectors.mapping(AttributeVO::getAttributeValue, Collectors.toList())
                            ));
                    objRenameDTO.setName(generateProductSpectrumName(ibaAttribute));
                    objRenameDTO.setOid(key);
                    objRenameDTO.setOtype(TableTypeConstrant.TY_PART_OTYPE);
                    objRenameDTOS.add(objRenameDTO);
                }
                typlmObjsRenameService.batchRenameIdentityAndName(objRenameDTOS, false);

                UserDO user = TyAccountContext.getUser();

                List<MaterialSapSyncDO> materialSapSyncDOList = new ArrayList<>();
                for (RTClassificationServiceImpl.DescriptionResult descriptionResult : effectiveDescriptions) {
                    MaterialSapSyncDO materialSapSyncDO = new MaterialSapSyncDO();
                    materialSapSyncDO.setId(String.valueOf(snowflakeIdComponent.getInstance().nextId()));
                    materialSapSyncDO.setMaterialCode(descriptionResult.getResultEntityVO().getObjectNumber());
                    materialSapSyncDO.setMaterialVersion(descriptionResult.getResultEntityVO()
                                                                 .getVersion() + "." + descriptionResult.getResultEntityVO()
                            .getIterationid());
                    materialSapSyncDO.setIsSendToSap("0");
                    materialSapSyncDO.setCreateTime(new Date());
                    materialSapSyncDO.setEffectiveTime(new Date());
                    materialSapSyncDO.setUpdateUser(user.getOid().toString()); // 或者从上下文中获取当前用户
                    materialSapSyncDOList.add(materialSapSyncDO);
                }
                // 批量插入到数据库
                if (CollUtil.isNotEmpty(materialSapSyncDOList)) {
                    materialSapSyncMapper.batchInsertMaterialSapSync(materialSapSyncDOList);
                }
            }
        }
    }


    /**
     * 生成产品型谱名称
     */
    public String generateProductSpectrumName(Map<String, List<String>> ibaAttribute) {
        StringBuilder name = new StringBuilder();
        String productType = getAttributeValue(ibaAttribute, "productType");
        if (StringUtils.isNotBlank(productType)) {
            name.append(productType);
        }
        String historicalModels = getAttributeValue(ibaAttribute, "HistoricalModels");
        if (StringUtils.isNotBlank(historicalModels)) {
            name.append("(").append(historicalModels).append(")");
        }
        return String.valueOf(name);
    }

    private String getAttributeValue(Map<String, List<String>> ibaAttribute, String key) {
        return ibaAttribute.containsKey(key) && CollUtil.isNotEmpty(ibaAttribute.get(key)) ? ibaAttribute.get(key).get(
                0) : "";
    }

}